package com.zsy.config;

import com.fasterxml.jackson.databind.ObjectMapper;

import com.zsy.interceptor.JwtAuthenticationTokenFilter;
import com.zsy.service.impl.SpringUserDetailsService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.config.BeanIds;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;

import static javax.management.Query.and;

@Configuration
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {

//    @Resource
//    private CaptchaCodeFilter captchaCodeFilter;

    @Resource
    private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;

    @Bean(name = BeanIds.AUTHENTICATION_MANAGER)
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 拦截
        http.authorizeHttpRequests()
                .antMatchers("/kaptcha","/authentication","/refreshtoken","/user/sendCode","/websocket/**").permitAll()
                //  authentication 类型是Optional<Authentication>，表示当前安全上下文中的认证信息，包含SecurityContext的用户信息，content原始http请求
                .anyRequest().access((authentication, context) -> {
                    // 获取当前用户的权限信息
                    Collection<? extends GrantedAuthority> authorities = authentication.get().getAuthorities();
                    // 获取原始request对象
                    HttpServletRequest request = context.getRequest();
                    // 拿到接口的绝对路径
                    String requestURI = request.getRequestURI();
                    // 创建一个AntPathMatcher实例，用于匹配url模式，AnPathMatcher 支持简单的通配符模式匹配
                    // 使用AntPathMatcher进行路径模式匹配
                    AntPathMatcher pathMatcher = new AntPathMatcher();
                    // 遍历用户的所有权限(GrantedAuthority对象),这些权限在认证后被加载到SecurityContext中
                    for (GrantedAuthority authority : authorities) {
                        // 检查当前权限是否是 SimpleGrantedAuthority 的实例，既权限是以字符串形式表示的标准权限
                        if (authority instanceof SimpleGrantedAuthority) {
                            // 获取权限的字符串表示形式，例如 "ROLE_ADMIN" 或者 "/admin/**"
                            String authorityString = authority.getAuthority();
                            // 使用 AntPathMatcher 将权限字符串与当前请求的url进行匹配
                            //如果权限字符串是一个url模式，而requestURL是实际请i去的资源路径，则检查他们是否匹配
                            if (pathMatcher.match(authorityString, requestURI)) {
                                // 如果权限和请求url匹配，则返回一个新的 AuthorizationDecision对象，表示授权通过，参数true表示授权通过
                                return new AuthorizationDecision(true);
                            }
                        }
                    }
                    // 如果没有任何权限匹配，则拒绝访问
                    return new AuthorizationDecision(false);
                });
        // 异常处理
        http.exceptionHandling()
                .accessDeniedHandler(((request, response, accessDeniedException) -> {
                    HashMap<String, Object> map = new HashMap<>();
                    map.put("msg", "禁止访问");
                    map.put("status", 403);
                    map.put("异常信息", accessDeniedException.getMessage());
                    response.setContentType("application/json;charset=UTF-8");
                    String s = new ObjectMapper().writeValueAsString(map);
                    response.getWriter().println(s);
                }));
        // session管理
        http.sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
                .and()
                //在Spring Security过滤器链中添加自定义过滤器，并指定该过滤器应该放置在哪个标准过滤器之前
                .addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
         // 记住我功能
        http.rememberMe().tokenValiditySeconds(7 * 24 * 3600);

        http.logout().logoutSuccessHandler(((request, response, authentication) -> {
            HashMap<String, Object> map = new HashMap<>();
            map.put("msg", "退出成功");
            map.put("status", 200);
            response.setContentType("application/json;charset=UTF-8");
            String s = new ObjectMapper().writeValueAsString(map);
            response.getWriter().println(s);
        }));
        //把生成验证码的方法放在校验权限之前
//        http.addFilterBefore(captchaCodeFilter, UsernamePasswordAuthenticationFilter.class);
        //解决跨域
        http.cors(c -> {
            CorsConfigurationSource source = request -> {
                CorsConfiguration config = new CorsConfiguration();
                config.setAllowedOrigins(Arrays.asList("*"));
                config.setAllowedMethods(Arrays.asList("*"));
                config.addAllowedHeader("*");
                return config;
            };
            c.configurationSource(source);
        });
        // 解除跨域保护
        http.csrf().disable();
    }
    /**
     * 注入加密类
     * @return
     */
    @Bean("passwordEncoder")
    public PasswordEncoder passwordEncoder(){
//        return new BCryptPasswordEncoder();
        // 返回一个自定义的 NoOpPasswordEncoder 实现
        return new PasswordEncoder() {
            @Override
            public String encode(CharSequence rawPassword) {
                // 不对密码进行编码（仅用于新注册或更改密码时）
                return rawPassword.toString();
            }
            @Override
            public boolean matches(CharSequence rawPassword, String encodedPassword) {
                // 直接比较明文密码
                return rawPassword.toString().equals(encodedPassword);
            }
        };

    }


    @Resource
    private SpringUserDetailsService userDetailsService;

    @Override
    protected void configure(AuthenticationManagerBuilder builder) throws Exception {
        // 加密方式认证
        builder.userDetailsService(userDetailsService)
                .passwordEncoder(passwordEncoder());
    }



}